//*************************************************************************************
// EGTB Generator Lookup Function - by bitboard it returns WDL and DTM values
//*************************************************************************************

#pragma once

#include "EndGameDbCommon.h"

namespace EndGameDB
{
	// Looks up the WDL and DTM value by entered bitboard and side tomove
	/////////////////////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxField, int BitsPerRow, bool UseOpenMP> 
	int Lookup(BB *p, int color, uint8* pDtmValue)
	{
		*pDtmValue = 0;
		// returns WIN LOSS DRAW or UNKNOWN for a BitBoard in a database lookup.
		int64 index;
		int bm, bk, wm, wk, bmrank=0, wmrank=0;
	
		uint32 *database;
		int reverse = 0;
		int value=UNKNOWN;
	
		BB revpos, orgpos;

		// set bm, bk, wm, wk, and ranks - bitcount is in bool.c
		wm = BitCountXX<BB>(p->wm);
		if(wm)
			wmrank = MSBxx<BB>(p->wm) / BitsPerRow;
		wk = BitCountXX<BB>(p->wk);
		bm = BitCountXX<BB>(p->bm);
		if(bm)
			bmrank = (MaxField - LSBxx<BB>(p->bm)) / BitsPerRow;	
		bk = BitCountXX<BB>(p->bk);
	
		if(bm+bk==0)
			return color==BLACK?LOSS:WIN;
		if(wm+wk==0)
			return color==WHITE?LOSS:WIN;

		// if this BitBoard is dominated by the "wrong" side, we have to
		// reverse it!
		if(bm+bk>wm+wk)
			reverse = 1;
		else 
		{
			if(wm+wk==bm+bk)
			{
				if(bk>wk)
					reverse = 1;
				else if(bk == wk)
				{
					if(bm > wm)
						reverse = 1;
					else if(bm==wm)
					{
						if(bmrank>wmrank)
							reverse = 1;
						else if(wmrank==bmrank)
						{
							// this is a self-mirror:
							// only look at BitBoards with black to move
							if(color==BLACK)
							{
								reverse = 1;
							}
						}
					}
				}
			}
		}

		if (reverse)
		{
			// white is dominating this BitBoard, change colors
			orgpos = *p;
			revpos.bm = RevertXX<BB>(p->wm);
			revpos.bk = RevertXX<BB>(p->wk);
			revpos.wm = RevertXX<BB>(p->bm);
			revpos.wk = RevertXX<BB>(p->bk);
			*p = revpos;
			color^=1;
		
			reverse = bm;
			bm = wm;
			wm = reverse;
		
			reverse = bk;
			bk = wk;
			wk = reverse;
		
			reverse = bmrank;
			bmrank = wmrank;
			wmrank = reverse;
		
			reverse = 1;
		}

		uint8* dtm = NULL;

		if(UseOpenMP)
		{
			database = GetRawDatabase(wm, wk, bm, bk, wmrank, bmrank, color, &dtm);
			if(database == NULL || dtm == NULL)
			{
				value = UNKNOWN;
			}
			else
			{
				BitBoardToIndexXX<BB>(p, &index);

				value = GetDatabaseValue(database, index);
				uint8 dtmValue = GetDTMValue(dtm, index);
		
				*pDtmValue = dtmValue;

			}
		}
		else
		{
			database = GetRawDatabaseNOMP(wm, wk, bm, bk, wmrank, bmrank, color, &dtm);
			if(database == NULL || dtm == NULL)
			{
				value = UNKNOWN;
			}
			else
			{
				BitBoardToIndexXX<BB>(p, &index);

				value = GetDatabaseValueNOMP(database, index);
				uint8 dtmValue = GetDTMValueNOMP(dtm, index);
		
				*pDtmValue = dtmValue;

			}
		}
	
		if(reverse)
		{
			// reset the BitBoard
			*p=orgpos;
		}
	
		return value;
	}

}